package com.hqully.smartfumehood.common.config;


import com.hqully.smartfumehood.shiro.JWTCredentialsMatcher;
import com.hqully.smartfumehood.shiro.MultiRealmAuthenticator;

import com.hqully.smartfumehood.shiro.NoSessionSubjectFactory;
import com.hqully.smartfumehood.shiro.filter.AnyRolesAuthorizationFilter;
import com.hqully.smartfumehood.shiro.filter.JWTFilter;
import com.hqully.smartfumehood.shiro.realm.JWTRealm;
import com.hqully.smartfumehood.shiro.realm.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AuthenticationStrategy;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.*;
/**
 * @description: shiro配置
 * @author liulingyu
 * @date 2022-05-06 21:10
 * @Version 1.0
 */
@Configuration
public class ShiroConfig {


    /**
    * @description: 配置禁用session的shiro工厂类
    * @date  2022/5/7 13:11
    * @author  liulingyu
    * @param
    * @return com.hqully.labmanage.shiro.NoSessionSubjectFactory
    */
    @Bean
    public NoSessionSubjectFactory noSessionSubjectFactory() {
        return new NoSessionSubjectFactory();
    }


    @Bean
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 为 Spring-Bean 开启对 Shiro 注解的支持
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator app = new DefaultAdvisorAutoProxyCreator();
        app.setProxyTargetClass(true);
        return app;

    }




    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        bean.setLoginUrl("/login");
        bean.setUnauthorizedUrl("/unAuthorized");
        HashMap<String, Filter> filter = new HashMap<>(16);
        filter.put("jwt",new JWTFilter());
        filter.put("anyRoles",new AnyRolesAuthorizationFilter());



        bean.setFilters(filter);



        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        filterMap.put("/v2/api-docs/**", "anon");
        filterMap.put("/webjars/springfox-swagger-ui/**", "anon");

//        filterMap.put("/UserWebSocket/**","anon");

        filterMap.put("/api/login" , "anon");
//        filterMap.put("/register" , "anon");
        filterMap.put("/api/get-info" , "anon");
        filterMap.put("/api/unauthorized/**", "anon");
        filterMap.put("/api/device-data/send-command-data/**", "anon");

        filterMap.put("/api/lab-manager/**" , "jwt,roles[admin]");
        filterMap.put("/api/unit/find-all-unit" , "jwt,anyRoles[admin,labManager]");
        filterMap.put("/api/unit/**" , "jwt,roles[admin]");
        filterMap.put("/api/**", "jwt");




        bean.setFilterChainDefinitionMap(filterMap);






        return bean;
    }


    @Bean
    public UserRealm userRealm(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //加密方式
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //加密次数
        hashedCredentialsMatcher.setHashIterations(2);

        UserRealm userRealm = new UserRealm();

        userRealm.setCredentialsMatcher(hashedCredentialsMatcher);


        return userRealm;
    }

    @Bean
    public JWTRealm jwtRealm(){
        JWTRealm jwtRealm = new JWTRealm();
        jwtRealm.setCredentialsMatcher(new JWTCredentialsMatcher());
        return jwtRealm;
    }

    /**
     * 配置 ModularRealmAuthenticator
     */
    /**
     *<p>自定义ModularRealmAuthenticator,处理多Realm情况下异常抛出问题</p>
     * @date 2022/5/7 16:20 <br>
     * @author liulingyu <br>
     * @param
     * @return org.apache.shiro.authc.pam.ModularRealmAuthenticator
     */
    @Bean
    public ModularRealmAuthenticator authenticator() {
        ModularRealmAuthenticator authenticator = new MultiRealmAuthenticator();
        // 设置多 Realm的认证策略，默认 AtLeastOneSuccessfulStrategy
        AuthenticationStrategy strategy = new FirstSuccessfulStrategy();

        authenticator.setAuthenticationStrategy(strategy);
        return authenticator;
    }


    /**
     *<p>禁用session, 不保存用户登录状态。保证每次请求都重新认证</p>
     * @date 2022/5/7 16:16 <br>
     * @author liulingyu <br>
     * @param
     * @return org.apache.shiro.mgt.SessionStorageEvaluator
     */
    @Bean
    protected SessionStorageEvaluator sessionStorageEvaluator() {
        DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        return sessionStorageEvaluator;
    }
    /**
     *<p>自定义shiro安全管理器</p>
     * @date 2022/5/7 16:17 <br>
     * @author liulingyu <br>
     * @param
     * @return org.apache.shiro.mgt.SecurityManager
     */
    @Bean
    public SecurityManager securityManager() {

        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();


        // 1.Authenticator
        securityManager.setAuthenticator(authenticator());

        securityManager.setSubjectFactory(noSessionSubjectFactory());

        // 2.Realm
        List<Realm> realms = new ArrayList<Realm>(16);
        realms.add(jwtRealm());
        realms.add(userRealm());
        securityManager.setRealms(realms);

        // 3.关闭shiro自带的session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();

        subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator());
        securityManager.setSubjectDAO(subjectDAO);



        return securityManager;
    }


}
